#include "client.h"

#include <iostream>

using namespace std;

Client::Client(asio::io_service& service_, const client_options& opt_)
: opt(opt_)
, service(service_)
, udpsock(service_)
, udpservice(service_, udpsock)
, tcplistener(service_)
{
	udpsock.open(opt.udp_server_addr.protocol());
	udpsock.bind(asio::ip::udp::endpoint(opt.udp_server_addr.address().is_v4() ? (asio::ip::address)asio::ip::address_v4::any() : (asio::ip::address)asio::ip::address_v6::any(), 0));

	tcplistener.open(opt.tcp_listen_addr.protocol());
	tcplistener.bind(opt.tcp_listen_addr);
	tcplistener.listen(16);

	handle_udp_receive(boost::system::error_code(), 0);
	handle_tcp_accept(boost::system::error_code(), ClientConnRef());
}

void Client::handle_udp_receive(const boost::system::error_code& e, std::size_t len)
{
	if (!e && len >= 4) {
		uint32 header = (udppackbuf[0] << 24) | (udppackbuf[1] << 16) | (udppackbuf[2] <<  8) | (udppackbuf[3] <<  0);
		if ((header & 0xff) == 0x02)
			udpservice.handle_read(udppackbuf, len, &udppeer);
		//else if (header == 0xff133703)
		//  do something?
		else
			cerr << "Invalid udp packet received." << endl;
	}
	if (e) {
		cerr << "Error receiving udp packet: " << e.message() << endl;
	}
	udpsock.async_receive_from(boost::asio::buffer(udppackbuf, udppackbufsize), udppeer,
		boost::bind(&Client::handle_udp_receive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)
	);
}

void Client::handle_tcp_accept(const boost::system::error_code& e, ClientConnRef conn)
{
	if (!e && conn) {
		conn->giveSelfRef(conn);
		conn->handleTcpAccept();
	}
	if (e) {
		cerr << "Error handling tcp accept: " << e.message() << endl;
		//Sleep(1000);
	}

	conn = ClientConnRef(new ClientConn(service, udpservice, opt));
	tcplistener.async_accept(conn->getTcpConn(),
		boost::bind(&Client::handle_tcp_accept, this, boost::asio::placeholders::error, conn)
	);
}

